ARouter 源码详解一
ARouter
的源码提供两个 SDK
,分别是面向不同的阶段,本身 API
这个 SDK
是面向运行期的 ,而 compiler
这个 SDK
则是作用于编译期的,我们首先分析一下 compiler
这个 SDK
。
BaseProcessor
这是注解处理器的基类,主要进行一些工具类的初始化还有一些赋值操作,源码如下:
public abstract class BaseProcessor extends AbstractProcessor {
Filer mFiler;
Logger logger;
Types types;
Elements elementUtils;
TypeUtils typeUtils;
// Module name, maybe its 'app' or others
String moduleName = null;
// If need generate router doc
boolean generateDoc;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
mFiler = processingEnv.getFiler();
types = processingEnv.getTypeUtils();
elementUtils = processingEnv.getElementUtils();
typeUtils = new TypeUtils(types, elementUtils);
logger = new Logger(processingEnv.getMessager());
Map<String, String> options = processingEnv.getOptions();
if (MapUtils.isNotEmpty(options)) {
// 获取用户配置的 moduleName
moduleName = options.get(KEY_MODULE_NAME);
// 是否需要生成路由表文档
generateDoc = VALUE_ENABLE.equals(options.get(KEY_GENERATE_DOC_NAME));
}
...
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public Set<String> getSupportedOptions() {
return new HashSet<String>() {{
this.add(KEY_MODULE_NAME);
this.add(KEY_GENERATE_DOC_NAME);
}};
}
}
这个基类主要是初始化工具类,比如 Filer、TypeUtils、Logger
等和获取用户配置的 moduleName
和 generateDoc
。
我们先看一下当初使用时是怎样配置的:
android {
defaultConfig {
...
//ARouter 配置
javaCompileOptions {
annotationProcessorOptions {
arguments = [ AROUTER_MODULE_NAME : project.getName(), AROUTER_GENERATE_DOC: "enable"]
}
}
}
}
很明显,基类就是对这两个值进行的处理,可能你觉得这两个值好像不一样,其实这是一个常量值,在 Consts
类里,我们看一下 Consts
类的部分常量:
// Options of processor
public static final String KEY_MODULE_NAME = "AROUTER_MODULE_NAME";
public static final String KEY_GENERATE_DOC_NAME = "AROUTER_GENERATE_DOC";
public static final String VALUE_ENABLE = "enable";
这些值跟配置里面的一模一样。因为 ARouter
支持多模块工程,所以需要配置模块名称。
InterceptorProcessor
该处理器主要是处理拦截器的,即处理 Interceptor
注解,主要的方法如下:
private void parseInterceptors(Set<? extends Element> elements) throws IOException {
if (CollectionUtils.isNotEmpty(elements)) {
logger.info(">>> Found interceptors, size is " + elements.size() + " <<<");
// Verify and cache, sort incidentally.
for (Element element : elements) {
if (verify(element)) { // Check the interceptor meta
logger.info("A interceptor verify over, its " + element.asType());
// 获取 Interceptor 注解类
Interceptor interceptor = element.getAnnotation(Interceptor.class);
// 先从缓存中获取,如果不为空,即设置了相同优先级的拦截器,会抛异常
// 这里就解释了为什么设置相同优先级会报错
Element lastInterceptor = interceptors.get(interceptor.priority());
if (null != lastInterceptor) { // Added, throw exceptions
throw new IllegalArgumentException(
String.format(Locale.getDefault(), "More than one interceptors use same priority [%d], They are [%s] and [%s].",
interceptor.priority(),
lastInterceptor.getSimpleName(),
element.getSimpleName())
);
}
// 添加到缓存中
interceptors.put(interceptor.priority(), element);
} else {
logger.error("A interceptor verify failed, its " + element.asType());
}
}
// Interface of ARouter.
// IInterceptor 接口
TypeElement type_ITollgate = elementUtils.getTypeElement(IINTERCEPTOR);
// IInterceptorGroup 接口
TypeElement type_ITollgateGroup = elementUtils.getTypeElement(IINTERCEPTOR_GROUP);
// 构建 Map<Integer, Class<? extends IInterceptor>>
ParameterizedTypeName inputMapTypeOfTollgate = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(Integer.class),
ParameterizedTypeName.get(
ClassName.get(Class.class),
WildcardTypeName.subtypeOf(ClassName.get(type_ITollgate))
)
);
// Build input param name.
// 构建成 Map<Integer, Class<? extends IInterceptor>> interceptors
ParameterSpec tollgateParamSpec = ParameterSpec.builder(inputMapTypeOfTollgate, "interceptors").build();
// Build method : 'loadInto'
// 构建方法 loadInto
MethodSpec.Builder loadIntoMethodOfTollgateBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(tollgateParamSpec);
// Generate
if (null != interceptors && interceptors.size() > 0) {
// Build method body
for (Map.Entry<Integer, Element> entry : interceptors.entrySet()) {
// 构建方法内容
loadIntoMethodOfTollgateBuilder.addStatement("interceptors.put(" + entry.getKey() + ", $T.class)", ClassName.get((TypeElement) entry.getValue()));
}
}
// Write to disk(Write file even interceptors is empty.)
// 生成类并写入硬盘
JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
TypeSpec.classBuilder(NAME_OF_INTERCEPTOR + SEPARATOR + moduleName)
.addModifiers(PUBLIC)
.addJavadoc(WARNING_TIPS)
.addMethod(loadIntoMethodOfTollgateBuilder.build())
.addSuperinterface(ClassName.get(type_ITollgateGroup))
.build()
).build().writeTo(mFiler);
logger.info(">>> Interceptor group write over. <<<");
}
}
该处理器主要做了以下操作:
- 找到所有的
Interceptor
注解元素并进行检验。 - 判断是否有相同优先级的拦截器,有则抛异常,没有则把当前元素放入缓存。
- 利用
poet
库进行参数的构建、方法的构建和类的构建。
以下是一个通过该注解处理器生成的类:
// 实现 IInterceptorGroup 接口
public class ARouter$$Interceptors$$app implements IInterceptorGroup {
@Override
public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
// key 是优先级,value 是对应的拦截器的 Class 类型
interceptors.put(8, TestInterceptor.class);
}
}
实际上生成的类的类名是 ARouter$$Interceptors$$xxx
形式的,最后的名称是对应的模块名(moduleName) ,我这里是在 app
模块,所以后面的 xxx
是 app
。
RouteProcessor
该处理器主要是处理路由的,即处理 Route
注解,具体的操作类似于拦截器,最终会生成如下几种不同的类:
ARouter$$Providers$$app
实际上生成的类的类名是 ARouter$$Providers$$xxx
,最后的名称对应的模块名(moduleName)
// 实现 IProviderGroup 接口
public class ARouter$$Providers$$app implements IProviderGroup {
@Override
public void loadInto(Map<String, RouteMeta> providers) {
// key 是服务接口的全类名,value 是一个 RouteMeta 类
providers.put("com.alibaba.android.arouter.facade.service.DegradeService", RouteMeta.build(RouteType.PROVIDER, DegradeServiceImpl.class, "/service/degrade", "service", null, -1, -2147483648));
providers.put("com.alibaba.android.arouter.facade.service.SerializationService", RouteMeta.build(RouteType.PROVIDER, JsonServiceImpl.class, "/service/json", "service", null, -1, -2147483648));
providers.put("com.alibaba.android.arouter.facade.service.PretreatmentService", RouteMeta.build(RouteType.PROVIDER, PretreatmentServiceImpl.class, "/service/pretreatment", "service", null, -1, -2147483648));
providers.put("com.fanda.zeng.arouterdemo.service.TestService", RouteMeta.build(RouteType.PROVIDER, TestServiceImpl.class, "/service/testService", "service", null, -1, -2147483648));
}
}
ARouter$$Root$$app
同理,类名最后面的 app
是模块名称,不同模块名称不一样。
// 实现 IRouteRoot 接口
public class ARouter$$Root$$app implements IRouteRoot {
@Override
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
// key 是分组名称,value 是对应的组的索引类
routes.put("service", ARouter$$Group$$service.class);
routes.put("test", ARouter$$Group$$test.class);
}
}
这个类体现了按需加载的方案,这是一个分组的 Root
类,负责管理所有的分组的索引类,当需要加载对应的组时,会找到相应的索引类,然后把索引类下面保存的所有页面路由加载进内存。
ARouter$$Group$$test
类名最后面的 test
是分组的名称,不同的分组不一样
// 实现 IRouteGroup 接口
public class ARouter$$Group$$test implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
// key 是路由地址 ,value 是 RouteMeta 类
atlas.put("/test/Test1Activity", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/test1activity", "test", null, -1, -2147483648));
atlas.put("/test/Test2Activity", RouteMeta.build(RouteType.ACTIVITY, Test2Activity.class, "/test/test2activity", "test", new java.util.HashMap<String, Integer>(){{put("url", 8); }}, -1, -2147483648));
atlas.put("/test/Test3Activity", RouteMeta.build(RouteType.ACTIVITY, Test3Activity.class, "/test/test3activity", "test", new java.util.HashMap<String, Integer>(){{put("testObjList", 11); put("testObj", 11); put("teacherName", 8); put("testPac", 10); put("testMap", 11); put("age", 3); }}, -1, 100));
atlas.put("/test/Test4Activity", RouteMeta.build(RouteType.ACTIVITY, Test4Activity.class, "/test/test4activity", "test", null, -1, -2147483648));
atlas.put("/test/TestFragment", RouteMeta.build(RouteType.FRAGMENT, TestFragment.class, "/test/testfragment", "test", null, -1, -2147483648));
atlas.put("/test/webview", RouteMeta.build(RouteType.ACTIVITY, TestWebviewActivity.class, "/test/webview", "test", new java.util.HashMap<String, Integer>(){{put("url", 8); }}, -1, -2147483648));
}
}
AutowiredProcessor
该处理器是用来处理 Autowired
注解的,用于生成数据自动注入的辅助类,自动注入时需要调用如下方法:
ARouter.getInstance().inject(this);
其实就是调用这里生成的辅助类的 inject
方法,我们看一下生成的类:
// 实现 ISyringe 接口
public class Test3Activity$$ARouter$$Autowired implements ISyringe {
private SerializationService serializationService;
@Override
public void inject(Object target) {
// 获取自定义对象解析服务类
serializationService = ARouter.getInstance().navigation(SerializationService.class);
Test3Activity substitute = (Test3Activity)target;
// 字段赋值,不用是私有
substitute.name = substitute.getIntent().getStringExtra("teacherName");
substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
substitute.testPac = substitute.getIntent().getParcelableExtra("testPac");
if (null != serializationService) {
// 进行解析处理
substitute.testObj = serializationService.parseObject(substitute.getIntent().getStringExtra("testObj"), new com.alibaba.android.arouter.facade.model.TypeWrapper<TestObj>(){}.getType());
} else {
// 没有提供解析服务类,打印异常
Log.e("ARouter::", "You want automatic inject the field 'testObj' in class 'Test3Activity' , then you should implement 'SerializationService' to support object auto inject!");
}
}
}
先看一下该类的类名生成规则 Test3Activity$$ARouter$$Autowired
,很明显,最前面一段是对应的 Activity
或 Fragment
的名称,后面的是写死的模板名称。这里的赋值操作也说明了需要注入的字段不能是私有的,对于自定义的对象,需要 serializationService
进行解析。这个辅助类只是帮我们从 Intent
的 Bundle
中取出数据并进行赋值操作,如果不需要,完全可以自己手写赋值代码。
前面提到在 Providers
中保存的 value
和在分组索引的 value
中保存的都是 RouteMeta
类:
atlas.put("/test/Test1Activity", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/test1activity", "test", null, -1, -2147483648));
atlas.put("/test/Test1Activity", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/test1activity", "test", null, -1, -2147483648));
put("/test/TestFragment", RouteMeta.build(RouteType.FRAGMENT, TestFragment.class, "/test/testfragment", "test", null, -1, -2147483648));
那么我们看一下 RouteMeta
的字段:
public class RouteMeta {
private RouteType type; // Type of route,路由类型
private Element rawType; // Raw type of route
private Class<?> destination; // Destination,路由目标的 Class 类型
private String path; // Path of route,路由地址
private String group; // Group of route,路由分组
private int priority = -1; // 优先级,越小优先级越大
private int extra; // 额外的数据
private Map<String, Integer> paramsType; // Param type
private String name; // 在 Route 注解的 name 方法设置
}
其中 paramsType
是包含了所有注解了 Autowired
的属性的信息,key
为属性名,value
为属性类型,ARouter
将可被 intent
传递的数据类型定义了对应的 int
类型: BOOLEAN,BYTE,SHORT,INT,LONG,CHAR,FLOAT,DOUBLE,STRING,PARCELABLE,OBJECT
分别对应 0,1,2,3…
RouteType
是一个枚举,表示被注解类的路由类型:
public enum RouteType {
ACTIVITY(0, "android.app.Activity"),
SERVICE(1, "android.app.Service"),
PROVIDER(2, "com.alibaba.android.arouter.facade.template.IProvider"),
CONTENT_PROVIDER(-1, "android.app.ContentProvider"),
BOARDCAST(-1, ""),
METHOD(-1, ""),
FRAGMENT(-1, "android.app.Fragment"),
UNKNOWN(-1, "Unknown route type");
}
目前支持的是 ACTIVITY
、 PROVIDER
、 FRAGMENT
,ACTIVITY
和 FRAGMENT
是用来做路由跳转的,PROVIDER
用于提供服务实例的,用于模块解耦,这些类型的用法在 ARouter
使用篇已经讲过。